#include "gpu_program.h" 
#include "render_device.h"

c_gpu_program::~c_gpu_program()
{
    if (m_constant_table)
    {
        m_constant_table->Release();
        m_constant_table = NULL; 
    }
}

void c_gpu_program::set_vector4(const std::string& param_name, const c_vector4& val)
{
    m_constant_table->SetVector(c_render_device9::get_singleton_ptr()->get_d3d_device(), (D3DXHANDLE)(param_name.c_str()), (D3DXVECTOR4*)&val);
}

void c_gpu_program::set_matrix4x4(const std::string& param_name, const c_matrix4x4& val)
{
    m_constant_table->SetMatrix(c_render_device9::get_singleton_ptr()->get_d3d_device(), (D3DXHANDLE)(param_name.c_str()), (D3DXMATRIX*)&val); 
}

//////////////////////////////////////////////////////////////////////////

gpu_vertex_program_ptr create_vs_from_file(const std::string& file_name)
{
    ID3DXBuffer *shader_buf = NULL; 
    ID3DXConstantTable *constant_table = NULL; 
    bool result = compile_shader_from_file(file_name, std::string("vs_2_0"), &shader_buf, &constant_table); 
    gpu_vertex_program_ptr vs = gpu_vertex_program_ptr(new c_gpu_vertex_program(shader_buf, constant_table));
   
    return vs;
}

c_gpu_vertex_program::c_gpu_vertex_program(ID3DXBuffer *buf, ID3DXConstantTable *constant_table)
    : c_gpu_program(constant_table)
{
    BOOST_ASSERT(buf);
    HRESULT hr = c_render_device9::get_singleton_ptr()->get_d3d_device()->CreateVertexShader((DWORD*)(buf->GetBufferPointer()), &m_d3d9_vs); 
    BOOST_ASSERT(SUCCEEDED(hr));
    buf->Release(); 
}

c_gpu_vertex_program::~c_gpu_vertex_program()
{
    if (m_d3d9_vs)
    {
        m_d3d9_vs->Release();
        m_d3d9_vs = NULL;
    }
}

//////////////////////////////////////////////////////////////////////////
gpu_pixel_program_ptr create_ps_from_file(const std::string& file_name)
{
    ID3DXBuffer *shader_buf = NULL; 
    ID3DXConstantTable *constant_table = NULL; 
    bool result = compile_shader_from_file(file_name, std::string("ps_2_0"), &shader_buf, &constant_table); 
    gpu_pixel_program_ptr ps = gpu_pixel_program_ptr(new c_gpu_pixel_program(shader_buf, constant_table)); 
    return ps;
}

c_gpu_pixel_program::c_gpu_pixel_program(ID3DXBuffer *buf, ID3DXConstantTable *constant_table)
    : c_gpu_program(constant_table)
{
    BOOST_ASSERT(buf);
    HRESULT hr = c_render_device9::get_singleton_ptr()->get_d3d_device()->CreatePixelShader((DWORD*)(buf->GetBufferPointer()), &m_d3d9_ps); 
    BOOST_ASSERT(SUCCEEDED(hr));
    buf->Release(); 
}

c_gpu_pixel_program::~c_gpu_pixel_program()
{
    if (m_d3d9_ps)
    {
        m_d3d9_ps->Release();
        m_d3d9_ps = NULL;
    }
}

bool compile_shader_from_file(const std::string& file_name, const std::string& profile, ID3DXBuffer **pp_buf, ID3DXConstantTable **pp_constant_table)
{
    HRESULT hr; 
    ID3DXBuffer *shader_buf = NULL;
    ID3DXBuffer *err_buf = NULL;
    ID3DXConstantTable *constant_table = NULL; 

    hr = D3DXCompileShaderFromFileA(
        file_name.c_str(),
        NULL, NULL, 
        "main",
        profile.c_str(),
        D3DXSHADER_DEBUG,
        &shader_buf,
        &err_buf,
        &constant_table);
    
    *pp_buf = shader_buf; 
    *pp_constant_table = constant_table; 
    
    return SUCCEEDED(hr);
}